package org.sunrise.game.game.logic;

import com.google.protobuf.ByteString;
import org.sunrise.game.common.log.LogCore;
import org.sunrise.game.game.proto.TopicProto;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("unchecked")
public class ProtoParserUtils {

    private static final Map<Integer, Method> protoParserMap = new HashMap<>();

    private static final Map<String, String> topicMap = new HashMap<>();

    static {
        topicMap.put("TOPIC_TYPE_LOGIN", "LoginProto");
        topicMap.put("TOPIC_TYPE_MAP", "MapProto");
        topicMap.put("TOPIC_TYPE_HUMAN", "HumanProto");
        topicMap.put("TOPIC_TYPE_CHAT", "ChatProto");
    }

    public static Method getProtoParserClass(int packetType, int packetId) {
        return protoParserMap.get(generateKey(packetType, packetId));
    }

    public static void init() {
        for (Map.Entry<String, String> entry : topicMap.entrySet()) {
            int topicType = getTopicTypeFromName(entry.getKey());
            String protoClassName = entry.getValue();
            registerClientTopic(topicType, protoClassName);
        }
    }

    private static int getTopicTypeFromName(String topicTypeName) {
        try {
            Field field = TopicProto.TOPIC.class.getField(topicTypeName + "_VALUE");
            return field.getInt(null);
        } catch (Exception e) {
            return -1;
        }
    }

    public static int generateKey(int packetType, int packetId) {
        return packetType * 100000 + packetId;
    }

    public static void registerClientTopic(int packetType, String proto) {
        Class<?> enumClass;
        try {
            enumClass = Class.forName("org.sunrise.game.game.proto." + proto + "$FROM_CLIENT");
            Class<? extends Enum<?>> Class = (Class<? extends Enum<?>>) enumClass;
            if (Class == null) {
                LogCore.ServerStartUp.error("GameServer StartUp Failed, proto:{} invalid", proto + "FROM_CLIENT");
                System.exit(-1);
            }
            for (Enum<?> enumConstant : Class.getEnumConstants()) {
                if (!enumConstant.name().equals("UNRECOGNIZED")) {
                    Field valueField = enumClass.getDeclaredField("value");
                    valueField.setAccessible(true);
                    int value = (int) valueField.get(enumConstant);
                    String className = "org.sunrise.game.game.proto." + proto + "$M" + enumConstant.name();
                    Method method = null;
                    try {
                        method = java.lang.Class.forName(className).getMethod("parseFrom", ByteString.class);
                    } catch (Exception ignored) {}
                    if (method != null) {
                        protoParserMap.put(generateKey(packetType, value), method);
                    }
                }
            }
        } catch (Exception ignored) {}
    }
}
